﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Xml;

using DoxygenBrowser.Common.Model;
using System.Diagnostics;

namespace DoxygenBrowser.Common.Parser
{
	public class DocsetParser
  {
    private const string TOKEN_ELEMENT = "Token";
    private const string TOKENS_ELEMENT = "Tokens";
    private const string TOKENIDENTIFIER_ELEMENT = "TokenIdentifier";
    private const string NAME_ELEMENT = "Name";
    private const string APILANGUAGE_ELEMENT = "APILanguage";
    private const string TYPE_ELEMENT = "Type";
    private const string SCOPE_ELEMENT = "Scope";
    private const string PATH_ELEMENT = "Path";
    private const string ANCHOR_ELEMENT = "Anchor";

    public event EventHandler<TokenAddedEventArgs> TokenAddedEvent;
		public event ProgressChangedEventHandler ProgressChangedEvent;
		private long _position = 0;
		private long _length = 0;

		public DocsetParser()
    {

    }

		public void Parse(Stream stream)
    {

			using (XmlTextReader xmlReader = new XmlTextReader(stream))
    {
				_position = 0;
				_length = stream.Length;
				while (xmlReader.Read())
      {
					switch (xmlReader.NodeType)
        {
          case XmlNodeType.Element:
            {
								if (xmlReader.Name == TOKEN_ELEMENT)
              {
									ParserToken(xmlReader.ReadSubtree());
									updatePosition(stream.Position);
              }
            }
            break;
					}
				}
			}
		}

		private void updatePosition(long position)
		{
			if (_position != position)
			{
				_position = position;
				int progressPercent = 0;				
				if (_length != 0)
				{
					progressPercent = (int)((_position * 100) / _length);
				}
				onProgressEvent(progressPercent);
			}
        }
        
		private void onProgressEvent(int progressPercent)
		{
			if (ProgressChangedEvent != null)
			{
				ProgressChangedEvent(this, new ProgressChangedEventArgs(progressPercent, null));
      }
    }

    private XmlReader createXmlReader(Stream streamReader)
    {
      XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
      xmlReaderSettings.CheckCharacters = false;
      XmlReader result = XmlReader.Create(streamReader, new XmlReaderSettings());
      return result;
    }

    private void ParserToken(XmlReader reader)
    {
      TokenIdentifier tokenIdentifier = null;
      FileLocation fileLocation = new FileLocation();
      while (reader.Read())
      {
        if(reader.NodeType == XmlNodeType.Element)
        {
          switch(reader.Name)
          {
            case TOKENIDENTIFIER_ELEMENT:
              tokenIdentifier = ParserTokenIdentifier(reader.ReadSubtree());
              break;
            case PATH_ELEMENT:
              fileLocation.Path = reader.ReadElementString();
              break;
            case ANCHOR_ELEMENT:
              fileLocation.Anchor = reader.ReadElementString();
              break;
          }          
        }
      }
      OnAddData(tokenIdentifier, fileLocation);
    }

    private TokenIdentifier ParserTokenIdentifier(XmlReader reader)
    {
      TokenIdentifier tokenId = new TokenIdentifier();
      reader.ReadStartElement();
      while (reader.Read())
      {
        if (reader.NodeType == XmlNodeType.Element)
        {
          switch (reader.Name)
          {
            case NAME_ELEMENT:
              tokenId.Name = reader.ReadString();
              break;
            case APILANGUAGE_ELEMENT:
              tokenId.APILanguage = reader.ReadString();
              break;
            case TYPE_ELEMENT:
              tokenId.Type = reader.ReadString();
              break;
            case SCOPE_ELEMENT:
              tokenId.Scope = reader.ReadString();
              break;
          }
          reader.ReadEndElement();
        }
        
      }

      return tokenId;
    }

    public virtual void OnAddData(TokenIdentifier tokenIdentifier, FileLocation fileLocation)
    {
      if(TokenAddedEvent != null)
      {
        TokenAddedEvent(this, new TokenAddedEventArgs(tokenIdentifier, fileLocation));
      }
    }
  }
}
